package com.study.spmongodb.threadlocal;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author study
 * @version 1.0
 * @date 2020/11/5 16:02
 * https://www.letianbiji.com/java/java-threadlocal.html
 */
public class ThreadLocalTest02 {
    private static ThreadLocal<Integer> logId = new ThreadLocal<>();

    private static AtomicLong taskId = new AtomicLong();  // 生成任务编号

    // 加强版 Runnable
    public static class EnhancedRunnable implements Runnable {

        private Runnable delegate;

        public EnhancedRunnable(Runnable task) {
            delegate = task; // 在当前线程执行
        }

        public static EnhancedRunnable of(Runnable task) {
            return new EnhancedRunnable(task);
        }

        @Override
        public void run() {  // 在另外一个线程执行
            System.out.println("清理 logId 的值");
            showLogId();
            logId.remove(); // 清理 logId 的值
            delegate.run();
        }
    }

    public static void showLogId() {
        System.out.printf("%s : %s\n", Thread.currentThread().getName(), logId.get());
    }

    public static void main(String[] args) throws InterruptedException {
        showLogId();
        logId.set(10);
        showLogId();

        // 只有一个线程的线程池，该线程会复用
        ExecutorService executorService = Executors.newFixedThreadPool(1);

        // 提交 EnhancedRunnable 类型的任务
        executorService.submit(EnhancedRunnable.of(() -> {
            Thread.currentThread().setName("task-" + taskId.addAndGet(1));
            showLogId();
            logId.set(20);
            showLogId();
        }));

        // 再提交一个 EnhancedRunnable 类型的任务
        executorService.submit(EnhancedRunnable.of(() -> {
            Thread.currentThread().setName("task-" + taskId.addAndGet(1));
            showLogId();
            logId.set(30);
            showLogId();
        }));

        // 关闭线程池
        executorService.shutdown();
        // 等待至任务都执行完，最多等3秒
        executorService.awaitTermination(3, TimeUnit.SECONDS);

        showLogId();
    }
}
